package com.dsteiner.widgets.client.controller;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import com.dsteiner.widgets.client.Widgets.IFlowPanel;
import com.dsteiner.widgets.client.Widgets.IHTML;
import com.dsteiner.widgets.client.Widgets.ILazyWidget;
import com.dsteiner.widgets.client.Widgets.IListBox;
import com.dsteiner.widgets.client.Widgets.IWidget;
import com.dsteiner.widgets.client.Widgets.WidgetListenerAdapter;
import com.dsteiner.widgets.client.model.PaginationModel;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.InlineHTML;
import com.google.gwt.user.client.ui.Widget;

public class PaginationController {

	private PaginationModel paginationModel;
	private IFlowPanel pagesContentPanel;
	private IHTML nextLink;
	private IHTML prevLink;
	private IWidget pagePanel;
	private IHTML resultsHtml;
	private IListBox itemsPerPageListBox;

	public void registerItemsPerPageListBox(final IListBox itemsPerPageListBox) {
		this.itemsPerPageListBox = itemsPerPageListBox;
		itemsPerPageListBox.addChangeHandler(new ChangeHandler(){
			public void onChange(ChangeEvent event) {
				paginationModel.setItemsPerPage(new Integer(itemsPerPageListBox.getSelectedValue()));
			}
		});
	}

	public void registerNextLink(IHTML nextLink) {
		this.nextLink = nextLink;
		nextLink.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event) {
				paginationModel.setPage(paginationModel.getPage()+1);
			}
		});
	}

	public void registerPagePanel(IWidget pagePanel) {
		this.pagePanel = pagePanel;
	}

	public void registerPagesContentPanel(IFlowPanel pagesContentPanel) {
		this.pagesContentPanel = pagesContentPanel;
	}

	public void registerPaginationModel(PaginationModel paginationModel) {
		this.paginationModel = paginationModel;
		paginationModel.addPropertyChangeListener("count", new PropertyChangeListener(){
			public void propertyChange(PropertyChangeEvent evt) {
				updateVisibility();
				updatePagesContentLinks();
				updateResultsHtml();
			}
		});
		paginationModel.addPropertyChangeListener("page", new PropertyChangeListener(){
			public void propertyChange(PropertyChangeEvent evt) {
				updateVisibility();
				updatePagesContentLinks();
				updateResultsHtml();
			}
		});
		paginationModel.addPropertyChangeListener("itemsPerPage", new PropertyChangeListener(){
			public void propertyChange(PropertyChangeEvent evt) {
				updateVisibility();
				updatePagesContentLinks();
				updateResultsHtml();
				updateItemsPerPageSelection();
			}
		});
	}
	
	public void registerPaginationWidget(ILazyWidget paginationWidget) {
		paginationWidget.addWidgetListener(new WidgetListenerAdapter() {
			@Override
			public void onAttach(IWidget widget) {
				updateVisibility();
				updatePagesContentLinks();
				updateResultsHtml();
			}
		});
	}

	public void registerPrevLink(IHTML prevLink) {
		this.prevLink = prevLink;
		prevLink.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event) {
				paginationModel.setPage(paginationModel.getPage()-1);
			}
		});
	}

	public void registerResultsHtml(IHTML resultsHtml) {
		this.resultsHtml = resultsHtml;
	}

	private Widget createPageLink(final int page) {
		int currentPage = paginationModel.getPage();
		String html;
		if(currentPage == page)
			html = "<strong>"+(page+1)+"</strong>";
		else
			html = "<a href=\"javascript:void(0);\">"+(page+1)+"</a>";
			
		InlineHTML pageLink = new InlineHTML(
				html);
		pageLink.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event) {
				paginationModel.setPage(page);
			}
		});
		return pageLink;
	}

	private void updateItemsPerPageSelection() {
		int itemsPerPage = paginationModel.getItemsPerPage();
		for (int i = 0; i < itemsPerPageListBox.getItemCount(); i++) {
			String value = itemsPerPageListBox.getValue(i);
			if(Integer.parseInt(value) == itemsPerPage){
				itemsPerPageListBox.setSelectedIndex(i);
				break;
			}
		}
	}

	private void updatePagesContentLinks() {
		int count = paginationModel.getCount();
		int itemsPerPage = paginationModel.getItemsPerPage();
		int page = paginationModel.getPage();

		int pagesCount = count / itemsPerPage + (count % itemsPerPage > 0 ? 1 : 0);
		int pageOffset = 2;
		
		pagesContentPanel.clear();
		pagesContentPanel.add(createPageLink(0));
		if(page - pageOffset > 0)
			pagesContentPanel.add(new InlineHTML("..."));
		else
			pagesContentPanel.add(new InlineHTML(","));
			
		int endPageCount = Math.min(page + pageOffset, pagesCount-1);
		for (int i = page - pageOffset; i < endPageCount; i++) {
			if(i <= 0 || i >= pagesCount-1)
				continue;
			
			pagesContentPanel.add(createPageLink(i));
			if(i < (endPageCount - 1))
				pagesContentPanel.add(new InlineHTML(","));
		}
		
		if(page + pageOffset < pagesCount-1)
			pagesContentPanel.add(new InlineHTML("..."));
		else if(pagesCount > 2)
			pagesContentPanel.add(new InlineHTML(","));
		pagesContentPanel.add(createPageLink(pagesCount-1));
	}

	private void updateResultsHtml() {
		int count = paginationModel.getCount();
		int itemsPerPage = paginationModel.getItemsPerPage();
		int page = paginationModel.getPage();
		
		int offset = page * itemsPerPage;
		
		String result = offset + " - " + Math.min(offset+itemsPerPage, count) + " de " + count 
		+ " mostrado "; 
		resultsHtml.setHTML(result);
	}

	private void updateVisibility() {
		int count = paginationModel.getCount();
		int itemsPerPage = paginationModel.getItemsPerPage();
		int page = paginationModel.getPage();
		
		int offset = page * itemsPerPage;
		nextLink.setVisible(offset + itemsPerPage < count);
		prevLink.setVisible(page > 0);
		pagePanel.setVisible(count > itemsPerPage);
		itemsPerPageListBox.setVisible(count > 10);
	}
}